module aru_arb_rdgen_broadcast (
    input logic                             clk,
    input logic                             rst_n,
          aru_arb_rdgen_cfg_if.broadcast_in u_aru_cfg_if,
          aru_payload_if.in                 u_aru_payload_in_if,
          aru_payload_if.out                u_aru_payload_out_if

);
    logic lst_req_in_instr;
    logic ctrl_rdy, ctrl_vld;
    assign ctrl_vld = ~ctrl_rdy;
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            ctrl_rdy <= 1'b1;
        end else if (ctrl_rdy == 1'b0) begin
            if (u_aru_payload_out_if.vld && u_aru_payload_out_if.rdy && lst_req_in_instr) begin
                ctrl_rdy <= 1'b1;
            end
        end else begin
            if (u_aru_cfg_if.vld && u_aru_cfg_if.rdy) begin
                ctrl_rdy <= 1'b0;
            end
        end
    end

    assign lst_req_in_instr = u_aru_payload_out_if.sdb.eom && u_aru_payload_out_if.sdb.eon;

    aru_dat_t dat_broadcast;
    aru_dat_t dat_delayed;
    aru_sdb_t sdb_delayed;

    always_comb begin
        for (int m0_idx = 0; m0_idx < `P_ARU; m0_idx = m0_idx + 1) begin
            for (int n0_idx = 0; n0_idx < `N0; n0_idx = n0_idx + 1) begin
                case ({
                    u_aru_cfg_if.broadcast_m, u_aru_cfg_if.broadcast_n
                })
                    2'b00: dat_broadcast = u_aru_payload_in_if.dat;
                    2'b01: dat_broadcast[m0_idx*`N0+n0_idx] = u_aru_payload_in_if.dat[n0_idx];
                    2'b10: dat_broadcast[m0_idx*`N0+n0_idx] = u_aru_payload_in_if.dat[m0_idx];
                    2'b11: dat_broadcast[m0_idx*`N0+n0_idx] = u_aru_payload_in_if.dat[0];
                endcase
            end
        end
    end

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            dat_delayed <= 'd0;
            sdb_delayed <= 'd0;
        end else begin
            dat_delayed <= dat_broadcast;
            sdb_delayed <= u_aru_payload_in_if.sdb;
        end
    end

    logic has_data;
    logic up_vld, up_rdy, down_vld, down_rdy;
    assign up_vld   = u_aru_payload_in_if.vld;
    assign down_rdy = u_aru_payload_out_if.rdy;
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            has_data <= 'd0;
        end else if (has_data) begin
            if (~up_vld && down_rdy) begin
                has_data <= 'd0;
            end
        end else begin
            if (up_vld) begin
                has_data <= 'd1;
            end
        end
    end
    assign down_vld                 = has_data;
    assign up_rdy                   = (~has_data) || down_rdy;

    assign u_aru_payload_out_if.vld = ctrl_vld && down_vld;
    assign u_aru_payload_out_if.dat = dat_delayed;
    assign u_aru_payload_out_if.sdb = sdb_delayed;

    assign u_aru_payload_in_if.rdy  = up_rdy && ctrl_vld;
endmodule
